#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import sys
import json

from common.cleaner import clear
from common.common import exter_attack, output_result_file
from common.const import SysData, AuthType
from common.parse_parafile import ParamFileUtil
from common.logger import Logger
from common.exception.common_exception import ErrCodeException
from saphana.resource.saphana_cluster_manager import SaphanaClusterManage
from saphana.common.param_parse import Param
from saphana.common.saphana_const import SapConst
from generaldb.saphana.comm.saphana_const import SaphanaErrorCode, SaphanaJsonConstant, SaphanaConst
from saphana.resource.check_application import CheckApplication
from common.parse_parafile import get_env_variable, add_env_param

LOGGER = Logger().get_logger(filename="saphana.log")


class HanaResource:

    def __init__(self, pid, param_obj: Param):
        self.pid = pid
        self.param = param_obj

    @exter_attack
    def check_application(self):
        system_db_auth_type, username, protect_db_auth_type = self.modify_env_variables()
        resource_type = self.param.sub_type
        params = {
            SaphanaJsonConstant.SYSTEM_ID: self.param.app_extend_info.get(SaphanaJsonConstant.SYSTEM_ID),
            SaphanaJsonConstant.SYSTEM_DB_PORT: self.param.app_extend_info.get(SaphanaJsonConstant.SYSTEM_DB_PORT),
            SaphanaJsonConstant.PROTECT_DATABASE: SaphanaConst.SYSTEM_DB,
            SaphanaJsonConstant.SYSTEM_DB_USER: username,
            SaphanaJsonConstant.SYSTEMDB_AUTH_TYPE: system_db_auth_type,
            SaphanaJsonConstant.PROTECTDB_AUTH_TYPE: protect_db_auth_type
        }
        # 初始化 SaphanaClusterManage 时若 sid 不存在会抛出 ErrCodeException
        try:
            manager = SaphanaClusterManage(params, self.pid)
        except ErrCodeException as ex:
            error_params = Param.get_body_error_param(SaphanaErrorCode.ERROR_FOR_FRAMEWORK,
                                                SaphanaErrorCode.SYSTEM_ID_NOT_EXIST,
                                                "System id not exists!")
            LOGGER.error(f"System id {params.get(SaphanaJsonConstant.SYSTEM_ID)} not exists!")
            return error_params
        check_application = CheckApplication(self.pid, self.param, manager)
        if resource_type == SapConst.SAPHANA_DATABASE:
            params = {
                SaphanaJsonConstant.SYSTEM_ID: self.param.app_extend_info.get(SaphanaJsonConstant.SYSTEM_ID),
                SaphanaJsonConstant.SYSTEM_DB_PORT: self.param.app_extend_info.get(SaphanaJsonConstant.SYSTEM_DB_PORT),
                SaphanaJsonConstant.PROTECT_DATABASE: self.param.application.get("name", ""),
                SaphanaJsonConstant.SYSTEM_DB_USER: username,
                SaphanaJsonConstant.SYSTEMDB_AUTH_TYPE: system_db_auth_type,
                SaphanaJsonConstant.PROTECTDB_AUTH_TYPE: protect_db_auth_type
            }
            database_manger = SaphanaClusterManage(params, self.pid)
            return check_application.check_saphana_database(database_manger)
        if resource_type == SapConst.SAPHANA_INSTANCE:
            return check_application.check_saphana_instance(manager)
        error_message = "This type is not allowed !"
        params = Param.get_body_error_param(SaphanaErrorCode.ERROR_FOR_FRAMEWORK, SaphanaErrorCode.
                                            ERROR_PARAM,
                                            error_message)
        LOGGER.error(error_message)
        return params

    @exter_attack
    def remove_protect(self):
        check_application = CheckApplication(self.pid, self.param)
        if not check_application.remove_protect():
            LOGGER.warning("Fail to clean log mount path")
        return Param.get_body_error_param(SaphanaErrorCode.SUCCESS_FOR_FRAMEWORK,
                                          SaphanaErrorCode.SUCCESS_FOR_FRAMEWORK, "")

    def modify_env_variables(self):
        protect_db_auth_type = get_env_variable(f"{SaphanaJsonConstant.APPLICATION}_{SaphanaJsonConstant.AUTH}_" \
                                                f"{SaphanaJsonConstant.AUTH_TYPE}_{self.pid}")
        instance_auth_pwd = f"{SaphanaJsonConstant.APPLICATION}_{SaphanaJsonConstant.AUTH}_" \
              f"{SaphanaJsonConstant.EXTEND_INFO}_" \
              f"{SaphanaJsonConstant.INSTANCE_AUTH}_{self.pid}"
        instance_auth_str = get_env_variable(instance_auth_pwd)
        if int(protect_db_auth_type) == AuthType.APP_PASSWORD.value:
            db_pwd = f"{SaphanaJsonConstant.APPLICATION}_{SaphanaJsonConstant.AUTH}_" \
                     f"{SaphanaJsonConstant.AUTH_PWD}_{self.pid}"
            db_name = f"{SaphanaJsonConstant.APPLICATION}_{SaphanaJsonConstant.AUTH}_" \
                      f"{SaphanaJsonConstant.AUTH_KEY}_{self.pid}"
        else:
            db_name = ""
            db_pwd = f"{SaphanaJsonConstant.APP_ENV}_{SaphanaJsonConstant.AUTH}_{SaphanaJsonConstant.EXTEND_INFO}_" \
                     f"{SaphanaJsonConstant.KEY_INFO}_{self.pid}"
        password = get_env_variable(db_pwd)
        username = get_env_variable(db_name)
        add_env_param(SaphanaJsonConstant.DB_PASSWORD + self.pid, password)
        add_env_param(SaphanaJsonConstant.DB_USER + self.pid, username)
        if not instance_auth_str:
            system_db_auth_type = protect_db_auth_type
            clear(password)
            return system_db_auth_type, username, protect_db_auth_type
        instance_auth = json.loads(instance_auth_str)
        system_db_auth_type = instance_auth.get(SaphanaJsonConstant.AUTH_TYPE, "")
        protect_passord = instance_auth.get(SaphanaJsonConstant.AUTH_PWD, "")
        protect_username = instance_auth.get(SaphanaJsonConstant.AUTH_KEY, "")
        if int(system_db_auth_type) == AuthType.OTHER.value:
            protect_username = ""
            protect_passord = instance_auth\
                .get(SaphanaJsonConstant.EXTEND_INFO, {}).get(SaphanaJsonConstant.KEY_INFO, "")
        add_env_param(SaphanaJsonConstant.SYSTEM_DB_PASSWORD + self.pid, protect_passord)
        add_env_param(SaphanaJsonConstant.SYSTEM_DB_USER + self.pid, protect_username)
        clear(instance_auth)
        clear(password)
        clear(protect_passord)
        return system_db_auth_type, username, protect_db_auth_type


@exter_attack
def run():
    if len(sys.argv) < 3:
        LOGGER.error("Number of argv wrong. ")
        return SaphanaErrorCode.ERROR_PARAM
    func_type = sys.argv[1]
    pid = sys.argv[2]
    try:
        parm_cont_dict = ParamFileUtil.parse_param_file(pid)
    except Exception as ex:
        LOGGER.error(f"Parse param file failed.")
        return SaphanaErrorCode.ERROR_PARAM
    if not parm_cont_dict:
        LOGGER.error("Param is none.")
        return SaphanaErrorCode.ERROR_PARAM

    if func_type not in ("CheckApplication", "ListApplicationResource", "RemoveProtect"):
        LOGGER.error("Unknown command from command line!")
        return SaphanaErrorCode.ERROR_PARAM

    param = Param(parm_cont_dict, pid)
    resource = HanaResource(pid, param)
    execute_func = {"CheckApplication": resource.check_application, "RemoveProtect": resource.remove_protect}
    res_exec = execute_func.get(func_type)
    try:
        output = res_exec()
    except Exception as ex:
        LOGGER.exception("Execute cmd %s with exception.", func_type)
        return SaphanaErrorCode.ERROR_PARAM
    try:
        output_result_file(pid, output)
    except Exception as ex:
        LOGGER.error("Write result failed with error")
        return SaphanaErrorCode.ERROR_PARAM
    return SaphanaErrorCode.SUCCESS_FOR_FRAMEWORK


if __name__ == '__main__':
    for line in sys.stdin:
        SysData.SYS_STDIN = line
        break
    sys.exit(run())
